package com.esdk.utils;

import com.esdk.esdk;
import com.esdk.interfaces.Adder;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * @author ffychina@163.com
 * @since 2025.10.22
 * 用long+double处理数字计算，输出时可以智能输出最小类型，如int>long>double，并简化四舍五入的输出。
 * 经测试，用int和Integer、double和Double性能无差别，堆栈转换几乎没有成本。double会比int或long慢10倍，int与long性能无差别。
 * 并且发现了instanceof没有性能问题，1亿次只是增加了2-4ms的耗时，另外，调用多一个函数的成本几乎为0，所以函数为了重用和阅读应该拆分多几个。
 * */
public class EasyNumber <Num extends Number> extends Number implements Adder<Num>{
  private double dblTotal=0d;
  private long longTotal=0;
  public EasyNumber(){
  }

  public EasyNumber(Num number){
    add(number);
  }

  @Override
  public EasyNumber add(Num number){
    if(number==null)
      return this;
    else if(number instanceof Long || number instanceof Integer || number instanceof Short){
      add(number.longValue());
    }
    else{
      add(number.doubleValue());
    }
    return this;
  }

  public EasyNumber subtract( Num number){
    if(number instanceof Long || number instanceof Integer || number instanceof Short){
      subtract(number.longValue());
    }
    else{
      subtract(number.doubleValue());
    }
    return this;
  }
  public EasyNumber multiply(Num number){
    dblTotal=dblTotal*number.doubleValue();
    return this;
  }

  public EasyNumber divide(Num number){
    dblTotal=dblTotal/number.doubleValue();
    return this;
  }

  public EasyNumber divide(double dbl){
    dblTotal=dblTotal/dbl;
    return this;
  }
  public EasyNumber add(double dbl){
    dblTotal=dblTotal+dbl;
    return this;
  }

  public EasyNumber add(long val){
    longTotal+=val;
    return this;
  }
  public EasyNumber subtract(double dbl){
    dblTotal-=dbl;
    return this;
  }

  public EasyNumber subtract(long lng){
    longTotal-=lng;
    return this;
  }

  public EasyNumber multiply(double dbl){
    dblTotal=dblTotal*dbl;
    return this;
  }

  @Override public String toString(){
    return toNumber().toString();
  }

  public Number toNumber(){
    if(dblTotal==0d)
      return longTotal;
    else
      return doubleValue();
  }

  public BigDecimal toBigDecimal(){
    return new BigDecimal(doubleValue());
  }

  public int intValue(){
    return (int)doubleValue();
  }

  public long longValue(){
    return (long)doubleValue();
  }

  public float floatValue(){
    return (float)doubleValue();
  }

  public double doubleValue(){
    return dblTotal+longTotal;
  }

  public BigDecimal get(){
    return new BigDecimal(doubleValue());
  }

  public BigDecimal get(int holdDigit){
    return get().setScale(holdDigit,RoundingMode.HALF_EVEN);
  }

  public double round(int holdDigit){
    return EasyMath.round(doubleValue(),holdDigit);
  }

  public static void main(String[] args){
    EasyNumber adder = new EasyNumber();
    adder.add(2);
    esdk.tool.assertEquals(adder.toNumber(),2);
    adder.add(1/3d);
    esdk.tool.assertEquals(adder.round(3),2.333);
    esdk.tool.assertEquals(adder.doubleValue(),2.3333333333333335);
    esdk.tool.assertEquals(adder.toNumber(),2.3333333333333335);
    esdk.tool.assertEquals(adder.intValue(),2);
    adder = new EasyNumber();
    adder.add(1.5);
    esdk.tool.assertEquals(adder.intValue(),1);
    TimeMeter tm=TimeMeter.startNew();
    for(int i=1;i<=10000*10000;i++){
      adder.add(Long.valueOf((long)100.55));
    }
    esdk.sout("long/int类型计算耗时：",tm.getHumanElapse());
    esdk.tool.assertEquals(adder.toNumber(),1.00000000015E10);
    tm=TimeMeter.startNew();
    for(int i=1;i<=10000*10000;i++){
      adder.add(100.55);
    }
    esdk.sout("double类型计算耗时：",tm.getHumanElapse());
    esdk.tool.assertEquals(adder.toNumber(),2.0055000001885494E10);
    esdk.tool.printAssertInfo();
  }
}
